#include <string>
#include <iostream>
#include <fstream>
#include "NormalizationModule.h"
using namespace std;
/*******************************************************************/
CNormalizationModule::CNormalizationModule(void)
{
	m_ext = "nvf";
}
/*******************************************************************/
CNormalizationModule::~CNormalizationModule(void)
{
}
/*******************************************************************/
TDataSet CNormalizationModule::CalculateNormalizationValues( TDataSet &data )
{
	TDataSet retVal;
	TFeatureVector means, stdDev;
	CalculateAverages(data, means, stdDev); 
	m_means = means;
	m_stdDev = stdDev;
	retVal.push_back(means);
	retVal.push_back(stdDev);
	return retVal;
}
/*******************************************************************/
TDataSet CNormalizationModule::Normalize( TDataSet& data )
{
	TDataSet retVal; 
	// we're just applying the whitening transform
	// f' = f-mu/sigma

	if( !IsReady() )// this is dumb. fix it, make explicit
	{
		CalculateNormalizationValues( data );
	}
	int nfeatures = static_cast<int>(data[0].size());
	int nDataPts = static_cast<int>(data.size());
	// for each image
	double temp =0.00;
	double newVal = 0.00; 
	for( int i=0; i<nDataPts; i++ )
	{
		for(int j=0; j<nfeatures; j++ )
		{
			temp = data[i][j];
			if(m_stdDev[j] != 0 )
			{
				newVal = (temp-m_means[j])/m_stdDev[j];
				data[i][j] = newVal; 
			}
			else
			{
				data[i][j]= 0.00; 
			}
		}
	}

	return retVal;
}
/*******************************************************************/
TFeatureVector CNormalizationModule::Normalize( TFeatureVector& data )
{
	TFeatureVector retVal;
	if( !IsReady() )
	{
		return retVal; 
	}
	int nfeatures = static_cast<int>(data.size());
	for(int j=0; j<nfeatures; j++ )
	{
		if(m_stdDev[j] != 0.00 )
		{
			data[j] = (data[j]-m_means[j])/m_stdDev[j];
		}
		else
		{
			data[j]= 0.00; 
		}
	}
	return retVal;
}
/*******************************************************************/
bool CNormalizationModule::IsReady(void)
{
	return (m_means.size() > 0 && m_stdDev.size() > 0); 
}
/*******************************************************************/
bool CNormalizationModule::Load( string name, string path )
{
	bool retVal = false;
	string realFName = path+name+"."+m_ext;
	ifstream ifs;
	ifs.open(realFName.c_str());
	int sz = 0, idx = 0;
	double m=0.00, stdv=0.00;
	if( ifs.is_open() )
	{
		ifs >> sz;
		m_means.clear();
		m_stdDev.clear();
		while( idx < sz && ifs.good() )
		{
			ifs >> m >> stdv;
			m_means.push_back(m);
			m_stdDev.push_back(stdv);
			idx++;
		}
		if( idx == sz )
		{
			retVal = true;
		}
		ifs.close();
	}
	return retVal;
}
/*******************************************************************/
bool CNormalizationModule::Save( string name, string path ) 
{
	bool retVal = false;
	string realFName = path+name+"."+m_ext;
	ofstream ofs;
	ofs.open(realFName.c_str());
	int sz = static_cast<int>(m_means.size());
	if( ofs.is_open() )
	{
		ofs << sz;
		for( int i=0; i<sz; i++ )
		{
			ofs << m_means[i] << "\t" << m_stdDev[i] << endl; 
		}
	
		if( ofs.good() )
		{
			retVal = true;
		}
		ofs.close(); 
	}
	return retVal;
}
/*******************************************************************/
TFeatureVector CNormalizationModule::GetAllFeatures( TDataSet data, int feature )
{
	TFeatureVector retVal;
	TDataSetIter images;
	for( images = data.begin(); images != data.end(); ++images )
	{
		retVal.push_back(images->at(feature));
	}
	return retVal; 
}
/*******************************************************************/
void CNormalizationModule::CalculateAverages( TDataSet data, TFeatureVector& means, TFeatureVector& stdDev ) 
{
	int nfeatures = static_cast<int>(data[0].size());
	double nDataPts = static_cast<double>(data.size());
	for( int i=0; i<nfeatures; ++i )
	{
		TFeatureVector temp = GetAllFeatures( data, i );
		TFeatureVectorIter iter; 
		double accumulator = 0.00;
		for( iter = temp.begin(); iter != temp.end(); ++iter )
		{
			accumulator += *iter;
		}
		double mu = accumulator/nDataPts;
		accumulator = 0.00;
		for( iter = temp.begin(); iter != temp.end(); ++iter )
		{
			accumulator += (*iter-mu)*(*iter-mu);
		}
		double var = accumulator/nDataPts;
		means.push_back(mu);
		stdDev.push_back(sqrt(var)); 
	}
}
/*******************************************************************/